package cn.lijiajia3515.cairo.auth.framework.security.oauth2.resourceserver.jwt.authentication;

import cn.lijiajia3515.cairo.auth.framework.AccountRepository;
import cn.lijiajia3515.cairo.security.oauth2.jwt.CairoJwtPrincipal;
import cn.lijiajia3515.cairo.security.oauth2.resource.server.authentication.CairoJwtAuthenticationToken;
import lombok.Getter;
import lombok.Setter;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;

import java.util.Collection;
import java.util.Optional;

/**
 * jwt token 转 CairoAuthenticationToken
 */
public class CairoJwtAuthenticationConverter implements Converter<Jwt, AbstractAuthenticationToken> {

	@Getter
	@Setter
	private JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();

	private final AccountRepository repository;

	public CairoJwtAuthenticationConverter(AccountRepository repository) {
		this.repository = repository;
	}

	/**
	 * jwt
	 *
	 * @param jwt jwt
	 * @return authentication 认证实体
	 */
	@Override
	public AbstractAuthenticationToken convert(Jwt jwt) {
		CairoJwtPrincipal cairoJwt = new CairoJwtPrincipal(jwt);


		Collection<GrantedAuthority> authorities = grantedAuthoritiesConverter.convert(cairoJwt);

		if (cairoJwt.getGrantType() != null && new AuthorizationGrantType(cairoJwt.getGrantType()).equals(AuthorizationGrantType.AUTHORIZATION_CODE)) {
			String app = Optional.ofNullable(cairoJwt.getAppId())
				.or(() -> Optional.ofNullable(cairoJwt.getClientId()))
				.orElse(cairoJwt.getSubject());

			cairoJwt.setAccount(repository.getAccount(app, cairoJwt.getSubject()));
			authorities.addAll(repository.getAuthority(app, cairoJwt.getSubject()));

		}

		return new CairoJwtAuthenticationToken(cairoJwt, authorities);
	}

}
